﻿#region Header

/*
Behavioral Rating of Dancing Human Crowds based on Motion Patterns
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Drawing;
using Emgu.CV;
using Emgu.CV.Structure;
using paravili.Services;
using Sebarf.Services.Interfaces;

#endregion

namespace paravili.Steps {
	/// <summary>
	/// Equalizes the Histogram of the given image
	/// </summary>
	public class HistogramEqualizer : ProcessStepWithMeasurement<Image<Bgr, Byte>> {
		#region Public Properties

		[ConfigurabelBooleanValue(Name = "Histogram angleichen")]
		public bool IsEnable { get; set; }

		[ServiceRequest(IsOptional = true)]
		public IImageProviderService ImageProviderService { get; set; }

		[ConfigurabelStringValue(Name = "ImageProviderId")]
		public String ImageProviderId { get; set; }

		[ConfigurabelBooleanValue(Name = "ForwardImageToImageProvider")]
		public bool ForwardImageToImageProvider { get; set; }

		#endregion

		#region Public Methods

		public HistogramEqualizer() {
			ImageProviderId = "NextImageProvider.HistogramEqualizer";
			ForwardImageToImageProvider = false;
		}

		protected override Image<Bgr, byte> OnProcess(Image<Bgr, byte> toProcess) {
			Image<Bgr, byte> toReturn = toProcess;
			if (IsEnable) {
				var tmp = new Image<Bgr, byte>(new Size(toProcess.Width, toProcess.Height));
				tmp[0] = HistEqualize(toProcess[0]);
				tmp[1] = HistEqualize(toProcess[1]);
				tmp[2] = HistEqualize(toProcess[2]);
				toReturn = tmp;
			}
			if (ForwardImageToImageProvider) {
				ImageProviderService.SetImage(ImageProviderId, toReturn.Convert<Lab, byte>());
			}
			return toReturn;
		}

		#endregion

		#region Private Methods

		//int[] cntersnew2 = null;
		private Image<Gray, byte> HistEqualize(Image<Gray, byte> img) {
			//accumulate and normalize a histogramm through opencv
            var h = new Histogram(256, new RangeF(0, 256));
			h.Accumulate(new IImage[] { img });
			h.Normalize(1);
			
            
            var work = new Image<Gray, byte>(img.Size);

            //the opencv histogramm is a cumulative distribution function
            //
			var cntersnew = new double[256];
			var cntersnew2 = new int[256];

            //calculate the resulting new value from the distribution
			cntersnew[0] = 255 * h[0];
			cntersnew2[0] = (int)cntersnew[0];
			for (int i = 1; i < 256; i++) {
				double nval = cntersnew[i - 1] + 255 * h[i];
				cntersnew[i] = nval;
				cntersnew2[i] = (int)nval;
			}

            //apply to input image, replace the old value with the new value
			byte[, ,] dataImg = img.Data;
			byte[, ,] dataWork = work.Data;
			for (int i = 0; i < img.Width; i++) {
				for (int j = 0; j < img.Height; j++) {
					dataWork[j, i, 0] = (byte)cntersnew2[dataImg[j, i, 0]];
				}
			}

			return work;
		}

		#endregion
	}
}